package com.bitejiuyeke.job_publish.service.impl;

import com.bitejiuyeke.job_publish.common.AppResult;
import com.bitejiuyeke.job_publish.common.ResultCode;
import com.bitejiuyeke.job_publish.dao.VerificationCodeMapper;
import com.bitejiuyeke.job_publish.enums.DeleteStateEnum;
import com.bitejiuyeke.job_publish.enums.VerifyCodeStateEnum;
import com.bitejiuyeke.job_publish.enums.VerifyCodeTypeEnum;
import com.bitejiuyeke.job_publish.exception.ApplicationException;
import com.bitejiuyeke.job_publish.model.VerificationCode;
import com.bitejiuyeke.job_publish.service.IVerificationCodeService;
import com.bitejiuyeke.job_publish.utils.JsonUtils;
import com.bitejiuyeke.job_publish.utils.RedisUtils;
import com.bitejiuyeke.job_publish.utils.StringUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * @Author 比特就业课
 */
@Slf4j
@Service
public class VerificationCodeServiceImpl implements IVerificationCodeService {

    // 有效时间 5 分钟
    private static final int EFFECTIVE_TIME = 5 * 60;

    private static final String KEY_CODE_PREFIX = "KEY_CODE_PREFIX:TARGET:TYPE:";

    @Resource
    private RedisUtils redisUtils;
    @Resource
    private VerificationCodeMapper mapper;


    @Override
    public void create(VerificationCode record) {
        // 参数核验
        if (record == null || StringUtils.isEmpty(record.getCode())
                || StringUtils.isEmpty(record.getPhoneNum())
                || VerifyCodeTypeEnum.valueOf(record.getType()) == null) {
            log.info("参数不正确");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 构造数据
        Date now = new Date();
        record.setExpires(new Date(now.getTime() + EFFECTIVE_TIME));// 过期时间
        record.setCount(0); // 校验次数
        record.setState((byte) VerifyCodeStateEnum.SENT.getCode()); // 状态
        record.setDeleteState((byte) DeleteStateEnum.NORMAL.getCode()); // 删除状态
        record.setCreateTime(now); // 创建时间
        record.setUpdateTime(now); // 更新时间
        // 写入数据数
        int row = mapper.insert(record);
        if (row != 1) {
            // 记录日志
            log.info("新增验证码失败, phoneNum = " + record.getPhoneNum());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
        // 写入缓存
        redisUtils.set(buildKey(record), JsonUtils.writeValueAsString(record), EFFECTIVE_TIME);
        // 记录日志
        log.info("新增验证码成功, phoneNum = " + record.getPhoneNum() + ", code = " + record.getCode());
    }

    @Override
    public void verify(VerificationCode record) {
        // 参数核验
        if (record == null || StringUtils.isEmpty(record.getCode())
                || StringUtils.isEmpty(record.getPhoneNum())
                || VerifyCodeTypeEnum.valueOf(record.getType()) == null) {
            log.info("参数不正确");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 从缓存中获取验证码
        String content = (String) redisUtils.get(buildKey(record));
        if (StringUtils.isEmpty(content)) {
            log.info("缓存中没有找到相应的验证码. target = " + record.getPhoneNum() + ", type = " + record.getType());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CODE_VERIFY));
        }
        // 转换为对象
        VerificationCode cacheCode = JsonUtils.readValue(content, VerificationCode.class);
        // 开始校验
        if (!record.getCode().equals(cacheCode.getCode())) {
            log.info("验证码校验失败.target = " + record.getPhoneNum() + ", type = " + record.getType());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CODE_VERIFY));
        }
        // 校验通过删除缓存
        redisUtils.del(buildKey(record));
        // 更新数据库
        VerificationCode updateVC = new VerificationCode();
        updateVC.setId(cacheCode.getId());
        updateVC.setState((byte) VerifyCodeStateEnum.VERIFIED.getCode());
        updateVC.setUpdateTime(new Date());
        mapper.updateByPrimaryKeySelective(updateVC);
        log.info("回销验证码成功. target = " + record.getPhoneNum() + ", type = " + record.getType());

    }

    // 构造KEY
    private String buildKey(VerificationCode verificationCode) {
        return KEY_CODE_PREFIX + verificationCode.getPhoneNum() + ":" + verificationCode.getType();
    }
}
